﻿using System;
using System.Threading;
using Mirkuz.PowerManagement;

using Microsoft.WindowsMobile.Samples.Location;

namespace Mirkuz.TrailCompanion
{
    public class GPSManager: IDisposable
    {
        public event EventHandler NewFixAvailable;
        public event EventHandler DifficultReception;

        Thread _gpsthread;
        IntPtr _gpspwrreq;
        bool _end_thread;
        int _pollingseconds=60;
        GpsPosition _currentpos;
        Gps gps;

        public GPSManager()
        {
            _gpsthread = new Thread(new ThreadStart(GPS_Thread));
            _gpsthread.Name = "GPSThread";
        }

        public void Start()
        {
            _gpsthread.Start();
        }

        public void Stop()
        {
            _end_thread = true;
        }

        public int PollingSeconds
        {
            get { return _pollingseconds; }
            set {
                if (value >= 10)
                    _pollingseconds = value;
                else
                    _pollingseconds = 10;
            }
        }

        private void GPS_Thread()
        {
            int iretry = 0;
            DateTime lastfixtime=DateTime.Now;

            while(!_end_thread)
            {
                _currentpos = null;

                _gpspwrreq = PowerManager.SetRequirement("GPD0:", CEDEVICE_POWER_STATE.D0);

                Thread.Sleep(1000);
                gps = new Gps();
                gps.Open();

                retry:
                {
                    Thread.Sleep(5000);

                    try
                    {
                        GpsPosition p = gps.GetPosition();
                        int s = ((_pollingseconds+20)  < 60 ) ? 60 : (_pollingseconds+20);

                        if (p != null
                            && p.EllipsoidAltitudeValid
                            && p.LongitudeValid
                            && p.TimeValid
                            && p.LatitudeValid
                            && p.Time != null
                            )
                        {                            
                            if (Math.Abs((int)lastfixtime.Subtract(p.Time).TotalSeconds)>1)
                               _currentpos = p;

                            lastfixtime = p.Time;
                        }
                    }
                    catch { _currentpos = null; }
                    
                    if (!_end_thread)
                    {
                        if (_currentpos != null)
                            OnNewFixAvailable();
                        else
                        {
                            iretry++;
                            if (iretry >= 10)
                            {
                                iretry = 0;
                                OnDifficultReception();
                            }
                            goto retry;
                        }
                    }
                }
                
                gps.Close();
                gps = null;
                
                PowerManager.ReleaseRequirement(_gpspwrreq);

                for (int i = 5; (i < _pollingseconds) && !_end_thread;i++)
                    Thread.Sleep(1000);
            }            
        }

        public GpsPosition CurrentPosition
        {
            get { return _currentpos; }
        }

        public void OnNewFixAvailable()
        {
            if (NewFixAvailable != null)
                NewFixAvailable(this, null);
        }
        public void OnDifficultReception()
        {
            if (DifficultReception != null)
                DifficultReception(this, null);
        }

        #region IDisposable Members

        public void Dispose()
        {
            _end_thread = true;
            try { _gpsthread.Abort(); }
            catch { }

            if (gps != null)
            {
                try
                {
                    gps.Close();
                }
                catch { }
                try
                {
                    PowerManager.ReleaseRequirement(_gpspwrreq);
                }
                catch { }
            }

        }

        #endregion
    }
}
